/*
Copyright (c) 2025, 北京智慧物联科技有限公司.

简体中文
保留所有权利。依据GPL 2.0（以下简称"本许可"）进行许可。除非符合（遵守）本许可及以下条款，否则您不得使用此文件：

禁止任何未经授权的个人或组织以任何形式将本程序及其附属资料、创新、创意、架构设计、算法、衍生作品等用于任何商业目的、盈利活动、各类竞赛(比赛)、直播教学、录播教学、线下课程、书籍编写、教材编写、会议、培训、公益活动、项目课题、毕业设计、毕业论文、学术论文等。

本程序由版权持有人和贡献人“按原样”提供，不提供任何明示或暗示担保，包括但不局限于对适销性和特定用途适合性的暗示担保。在任何情况下，版权持有人或贡献人对因使用本程序而导致的任何直接、间接、附带、特殊、典型或后果性损害（包括但不限于购买替代商品或服务；使用损失、数据丢失或利润损失；业务中断）不承担任何责任，无论其如何产生，也不论其责任理论为何，无论是合同、严格责任还是侵权（包括疏忽或其他），即使已告知此类损害的可能性。

English
All rights reserved. Licensed under the GPL 2.0 (the "License"). You may NOT use this file except in compliance with the License and the following terms:

IT IS PROHIBITED FOR ANY UNAUTHORIZED PERSON OR ENTITY TO USE THIS PROGRAM AND ITS ANCILLARY DATA, INNOVATIONS, CONCEPTS, ARCHITECTURE DESIGN, ALGORITHMS, DERIVED WORKS, ETC., IN ANY FORM FOR COMMERCIAL PURPOSES, PROFIT-MAKING ACTIVITIES, VARIOUS COMPETITIONS (CONTESTS), LIVE TEACHING, PRE-RECORDED LESSONS, OFFLINE COURSES, BOOK WRITING, CONFERENCES, TRAININGS, PUBLIC WELFARE ACTIVITIES, PROJECTS, TOPICS, GRADUATION DESIGNS, DISSERTATIONS, THESES, AND OTHER APPLICATIONS.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h> 
#include "stdlib.h"
#include "ohos_init.h" // 用于初始化服务(services)和功能(features)
#include "cmsis_os2.h" // CMSIS-RTOS API V2

#include "soc_osal.h"
#include "errcode.h"

#include "iot_uart.h"
#include "pinctrl.h"
#include "uart.h" 
#include <time.h>  
#include "iot_gpio.h"   // OpenHarmony HAL API：IoT硬件设备操作接口-GPIO
#include "iot_gpio_ex.h"

// include 
#include "iot_sha256.h"
#include "iot_string.h"  
#include "iot_crc16.h"  
 
#include "uart_task.h"  
  
#include "iot_client.h" // SLE客户端接口

#define UART_BUFF_SIZE          1024 
#define UART_PORT 1 // UART2: RX（GPIO07引脚），TX（GPIO08引脚）

int sleep_radar = 1;            // =1是睡眠，=0是跌倒雷达

osThreadId_t g_radar_id= NULL;   // 线程ID 

static char *sts        = NULL;   
static char *cmd        = NULL;  
static char *value      = NULL;  
static char *result     = NULL;  
static char *action     = NULL;  
static char *timestamp  = NULL;  
 
//static unsigned char uart_buff[UART_BUFF_SIZE] = {0}; // 串口读取的原始数据   
static int report_open = 1;                 // 上报开关：1打开，0关闭。默认上报
static int t_len = 0;                               // 临时长度
static unsigned char t_buff[UART_BUFF_SIZE] = {0};  // 临时数据

// 公共参数
static unsigned char last8001 = 0;     // 人体存在  
static unsigned char last8002 = 0;     // 运动信息  

// 跌倒雷达
static unsigned char last8301 = 0;     // 跌倒 
static unsigned char last8305 = 0;     // 跌倒驻留 

// 睡眠雷达   
static unsigned char last8102 = 0;     // 呼吸 
static unsigned char last8502 = 0;     // 心跳 
 
static int bFalling  = 0;      // 进入跌倒状态，0表示未跌倒，1表示跌倒；跌倒报文次数，3次再另外上报自定义跌倒预警：83 0F
static int bPresence = 0;      // 进入有人状态， 0表无人，1表示有人
 
/***** 自定义指令 *****/

// 66 01 (hi3861版本)，上端查询hi3861固件
void read_hi3861_version(void){
    char *ver = "ws263e"; // hi3861_version();   // 读取ota文件内容

    sts = "0";   
    sprintf(cmd, "%02X%02X", 0x66, 0x01);
    sprintf(value, "%s", ver);                        // value: 版本字符串
    sprintf(result, "%d", 0x00);                      // result = 00
    sprintf(action, "hi3861 ver: %s", ver);           // 文本
    
    printf("+++ sts: %s, cmd: %s, value: %s, result: %s, action: %s \r\n",  sts,  cmd,  value, result, action);
     
    publish_radar_data(cmd, value, result, action, timestamp);  // 发布数据
} 


/***** 定时器创建 *****/
osTimerId_t g_timer_id9 = NULL;

void timer_callback(void *arg) {
    (void)arg;  
    osal_printk("*** timer   \r\n");
    //Query_Presence();   // 频繁查询人员存在，引发异常 
}

void timer_start_task(void) { 
    uint32_t timerDelay;
    osStatus_t status;  
    uint32_t exec1 = 1U;

    g_timer_id9 = osTimerNew(timer_callback, osTimerPeriodic, &exec1, NULL);
    if (g_timer_id9 != NULL) { 
        timerDelay = 60 * 100U;  // Hi3861: 1U=10ms, 100U=1S

        status = osTimerStart(g_timer_id9, timerDelay);
        if (status != osOK) {
            // Timer could not be started
        }
    } 
} 

// 停止定时器
void timer_stop_task(void) {   
    if(g_timer_id9) {
	    osStatus_t status = osTimerDelete(g_timer_id9);
        osal_printk("*** timer_stop_task() ... ok. status: %d.\r\n", status);
        g_timer_id9 = NULL;
    }
}
 


/***** 解析雷达数据协议 *****/
int printFlag = 0;
int packetLen = 10;  //根据协议，一包数据至少10个字节；但是 02A4（雷达固件版本返回报文的长度=9）

int radar_data_parse(unsigned char *uart_buff, int orginLen)   {   
    /*
    for (int j = 0; j < orginLen; j++) {
        printf("%02X ", uart_buff[j]);
    }
    printf("\r\n");
    */ 
 
    int len = orginLen;  

    // 复制数据：uart_buff => orginBuff    
    unsigned char *readBuff = malloc(orginLen+1);   
    if(readBuff){
        memset(readBuff, 0, orginLen+1);    
        memcpy(readBuff, uart_buff, orginLen);
        readBuff[orginLen] = '\0';
 
        if(printFlag==0) { 
            osal_printk("<== readBuff [%d]: ", orginLen);
            for (int j = 0; j < orginLen; j++) {
                osal_printk("%02X ", readBuff[j]);
            }
            osal_printk("\r\n");
        }
    }

    // 开始解析包内部数据 
    sts = "-1";       // sts，初始化状态为-1  

    if(readBuff[0]==0x53 && readBuff[1]==0x59){

        // 主动报文长度
        if(len>=packetLen ){
            sprintf(cmd, "%02X%02X", readBuff[2], readBuff[3]);     

            // 心跳包信息
            if( strcmp(cmd,"0101")==0 ){
                sts = "1";          // 不上报
            }

            //===== 人体存在雷达：80

            // 80 01 存在信息：0x00:无人，0x01:有人。设备主动上报
            // 80 81 存在信息：0x00:无人，0x01:有人。上位机查询
            else if( (strcmp(cmd,"8001")==0) || (strcmp(cmd,"8081")==0) ){
                sts = "0";    
                sprintf(value, "%02X", readBuff[6]);        // value: 00/01 
 
                if(strcmp(value,"00")==0) { 
                    sprintf(result, "%s", "0");      
                    sprintf(action, "%s", "absence");        //无人
                    bPresence = 0;
                    // 如果是无人状态，则后续不发送心跳和呼吸报文，但需要模拟发送一次为0的报文 
                } 
                else if(strcmp(value,"01")==0) {     
                    sprintf(result, "%s", "1");          
                    sprintf(action, "%s", "presence");      //有人
                    bPresence ++;

                    if(bPresence>3600){
                        bPresence = 1;                      // 防止超出int数据类型
                    }
                } 

                // 可能 0 或 1
                last8001 = readBuff[6];                     // 保存上一次8001指令的result(0/1)值 
            } 
            // 80 02 运动信息：0x00:无运动，0x01:静止，0x02:活跃
            else if( strcmp(cmd,"8002")==0 ){
                sts = "0";    
                sprintf(value, "%02X", readBuff[6]);        // value: 00/01/02
 
                if(strcmp(value,"00")==0) {
                    sprintf(result, "%s", "0");                 
                    sprintf(action, "%s", "none");          //无运动     
                } 
                else if(strcmp(value,"01")==0) {
                    sprintf(result, "%s", "1");             
                    sprintf(action, "%s", "still");         //静止     
                } 
                else if(strcmp(value,"02")==0) {
                    sprintf(result, "%s", "2");             
                    sprintf(action, "%s", "active");        //活跃     
                }  

                // 如果 8001 = absence，则不用发送
                if( last8001 == 0){ 
                    sts = "1";                              // 不发送标志=1
                }  

                // 可能 0、1、2
                last8002 = readBuff[6];  

                // 上端分析价值不大，不上报
                sts = "0";                                // 暂时不报数
            } 
            
            // 80 03 体动参数：每1秒，取值0-100 
            // 只有在跌倒时，需要捕捉体动参数。
            else if( strcmp(cmd,"8003")==0 ){
                sts = "0";   
                sprintf(value, "%02X", readBuff[6]);                        // value: 1A = 26
                sprintf(result, "%d", readBuff[6]);       
                sprintf(action, "moving parameter: %d", readBuff[6]);       // 体动参数：0-100 
 
                // 如果 8001 = absence，则不用发送
                if( last8001 == 0){ 
                    sts = "1";                              // 不发送标志=1
                }   

                sts = "0";                                // 暂时不报数
            } 
  
            // 83 01 跌倒状态。设备主动上报
            // 83 81 跌倒状态。上位机查询
            else if( strcmp(cmd,"8301")==0 || strcmp(cmd,"8381")==0 ){
                sts = "0";    
                sprintf(value, "%02X", readBuff[6]);   
                
                if(strcmp(value,"00")==0) {
                    sprintf(result, "%s", "0");           
                    sprintf(action, "%s", "no falling");        // 未跌倒
                    bFalling = 0;
                } 
                else if(strcmp(value,"01")==0) {
                    sprintf(result, "%s", "1");          
                    sprintf(action, "%s", "falling");           // 跌倒
                    bFalling ++ ;  

                    // 上端主动查询是否处于跌倒状态
                    if( bFalling>=1 ){
                        //hi_udelay(3 * 1000 * 1000);                 // 延迟3秒
                        //Query_Falling();   
                    }  
                } 

                // 如果 8001 = absence，则不用发送
                if( last8001 == 0){ 
                    //sts = "1";                                    // 不发送标志=1 
                }  

                // 可能 0 或 1
                last8301 = readBuff[6];
                //sprintf(last8301, "%s", result);                    // 保存上一次8301指令的result(0/1)值  
            }   
             
            // 83 05 静止驻留，01无驻留，02有驻留
            else if( strcmp(cmd,"8305")==0 ){
                sts = "0";    
                sprintf(value, "%02X", readBuff[6]);   
                
                if(strcmp(value,"00")==0) {
                    sprintf(result, "%s", "0");         
                    sprintf(action, "%s", "no still hold");         // 无静止驻留    
                } 
                else if(strcmp(value,"01")==0) {
                    sprintf(result, "%s", "1");             
                    sprintf(action, "%s", "still hold");            // 静止驻留    
                }     

                // 如果 8001 = absence，则不用发送
                if( last8001 == 0){ 
                    //sts = "1";                                      // 不发送标志=1
                }  

                // 如果 8301 = no falling，则不用发送
                if( last8301 == 0 ){
                    sts = "2";                                      // 不发送标志=1
                }  

                // 可能 0 或 1                    
                last8305 = readBuff[6];
                //sprintf(last8305, "%s", result);                    // 保存上一次8306指令的result(0/1)值      
            }    
             
        } 
        
    }

    //osal_printk("=== free(readBuff) \r\n");
    free(readBuff); // 释放内存

    // 发送至mqtt
    if (len>=packetLen) {      

        if( strcmp(sts, "0")==0 ){    
            osal_printk("+++ cmd: %s, value: %s, result: %s, action: %s \r\n", cmd, value, result, action);
  
            // 发布数据
            //publish_radar_data(cmd, value, result, action, timestamp);  // 发布数据
            
            char data[512] = {0} ;   //  
            sprintf(data, "%s_%s_%s_%s", cmd, value, result, action);

            // 向SLE服务端发送数据
            //char *data = "Hello from SLE client!\n";
            int ret = iot_client_send_data((uint8_t *)data, strlen(data));

            //osal_printk("==> publish ok. \r\n");    
        }

    }  
    else {
        osDelay(5);
    } 

    osDelay(5);
     
    return len;
}
 

// 回调函数
static void radar_callback(const unsigned char *buffer, uint16_t orginLen)
{   
    // 解析收到的数据  
    // 判断头部标记是否存在
    if( buffer[0]==0x53 && buffer[1]==0x59 ) {
        // 判断尾部标记
        if(buffer[orginLen-2]==0x54 && buffer[orginLen-1]==0x43) {
            // 完整一包，解析处理
            radar_data_parse(buffer, orginLen); 
            t_len = 0;  // 归0 
        }
        else {
            // 作为第一包，暂存，不解析
            t_len += orginLen;
            memcpy(t_buff, buffer, orginLen); 
        }
    }
    // 没有头部标记
    else {  
        // 判断尾部标记是否存在
        if(buffer[orginLen-2]==0x54 && buffer[orginLen-1]==0x43) {
            // 把新报文加入到 t_buff中 
            for (int k = 0; k<orginLen; k++){
                t_buff[t_len + k] = buffer[k];
            }
            t_len += orginLen;

            // 作为完整一包，解析处理
            radar_data_parse(t_buff, t_len);   
            t_len = 0;  // 归0 
        }
        else {
            // 把新报文加入到 t_buff中，暂存，不解析
            t_len += orginLen;
            for (int k = 0; k<orginLen; k++){
                t_buff[t_len + k] = buffer[k];
            }
        } 
    }    

}
 
  

// 回调函数
static void uart2_rx_callback(const void *orginBuf, uint16_t orginLen, bool error)
{ 
    (void)error; 
    
    // osal_printk("uart2_rx_callback: %s\n", (const char *)buffer); 
    // uapi_watchdog_kick(); // 踢狗，防止CPU占用过高导致看门狗复位 
    if(report_open==0 || orginLen==0)
        return;     // 不允许上报、数据为空   
   
    unsigned char *buffer = (unsigned char *)orginBuf;
    radar_callback(buffer, orginLen); 
}
 
 
// 雷达任务
static void uart_task(void)  {       
    // 1. 字符串初始化：3+7+33+17+65+17 = 142  
    sts     = malloc(2+1);  
    cmd     = malloc(6+1);  
    value   = malloc(32+1);  
    result  = malloc(16+1);  
    action  = malloc(64+1);  
    timestamp = malloc(16+1);     

    // 3. rader init
    uapi_uart_deinit(UART_PORT);
    IotUartAttribute g_uart_cfg = {115200, 8, 1, IOT_UART_PARITY_NONE, 100, 100, 0};
    IoTUartInit(UART_PORT, &g_uart_cfg);
    osDelay(10); 

    // 注册回调函数。在接收回调处理过程中接收到的UART数据，会直接丢弃
    // UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE:
    // 如果接收缓存已满，或者接收的数据量到达指定的数据长度，或者接收数据暂停，就触发数据接收回调 
    (void)uapi_uart_register_rx_callback(UART_PORT, 
        UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE,
        16, uart2_rx_callback);  
    osal_printk("*** uart init success. \r\n");    

    // 5. 设置SLE客户端 
    iot_client_init();  
    iot_wait_service_found(); 

    // 向SLE服务端发送数据
    char *data = ">>> Hello from SLE client!\n";
    int ret = iot_client_send_data((uint8_t *)data, strlen(data));
     
}

// 启动雷达报文线程，在外部启动
void radar_start_task(void) {  
    if(g_radar_id)
        return;   // 如果线程已经启动，则跳过

    //设置任务参数,并Start一个SensorTask任务线程
	osThreadAttr_t attr;  
	attr.name = "radar_start_task";
	attr.attr_bits = 0U;
	attr.cb_mem = NULL;
	attr.cb_size = 0U;
	attr.stack_mem = NULL;
	attr.stack_size = 4*1024;  //2048
    attr.priority = osPriorityNormal1;

    g_radar_id = osThreadNew((osThreadFunc_t)uart_task, NULL, &attr);
	if (g_radar_id == NULL){
		osal_printk("=!= radar_start_task() ... falied to create. \r\n");
	}else {
		osal_printk("*** radar_start_task() ... ok. g_radar_id = %d. \r\n", g_radar_id);
	}

    // 启动定时器
    timer_start_task();
}

// 停止雷达报数进程
void radar_stop_task(void) {   
    if(g_radar_id) {
	    osStatus_t status = osThreadTerminate(g_radar_id);
        osal_printk("*** radar_stop_task() ... ok. status: %d.\r\n", status);
        g_radar_id = NULL;
    }
}

//SYS_RUN(radar_start_task);
APP_FEATURE_INIT(radar_start_task);

